﻿// ---------------------------------------------------------------------------------------------------------------------
//   Copyright (c) SRT Solutions 2009. All rights reserved.
// ---------------------------------------------------------------------------------------------------------------------

namespace SRTSolutions.Elevate
{
    using global::System;
    using global::System.Collections.Generic;

    /// <summary>
    /// Contains extension methods for doing Through.
    /// </summary>
    public static class ThroughExtensions
    {
        /// <summary>
        /// Generates a sequence of numbers starting from the start number
        /// and walking until the end number is reached.
        /// </summary>
        /// <param name="start">The start number.</param>
        /// <param name="end">The end number.</param>
        /// <returns>the sequence of start through end by 1, or -1</returns>
        public static IEnumerable<int> Through(this int start, int end)
        {
            var step = start < end ? 1 : -1;

            return Through(start, end, step);
        }

        /// <summary>
        /// Generates a sequence of numbers starting from the start number
        /// and walking until the end number is reached using the given step.
        /// </summary>
        /// <param name="start">The start.</param>
        /// <param name="end">The end.</param>
        /// <param name="step">The step.</param>
        /// <returns>The sequence if start through end by step</returns>
        public static IEnumerable<int> Through(this int start, int end, int step)
        {
            if (step == 0)
                throw new ArgumentException("step cannot be zero.", "step");
            if (start < end && step < 0)
                throw new ArgumentException("step is negative when start value is less than end value.", "step");
            if (start > end && step > 0)
                throw new ArgumentException("step is positive when start value is greater than end value.", "step");

            return ThroughHelper(start, end, step);
        }

        private static IEnumerable<int> ThroughHelper(this int start, int end, int step)
        {
            for (int i = 0; ; i++)
            {
                var current = start + (i * step);

                if (start <= end && current > end)
                {
                    break;
                }
                else if (start >= end && current < end)
                {
                    break;
                }
                else
                {
                    yield return current;
                }
            }
        }
    }
}
